package com.yanqu.road.server.manager.cross.battle;

import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.dafuweng.*;
import com.yanqu.road.entity.config.goods.GoodsInfo;
import com.yanqu.road.entity.enums.activity.dafuweng.eDaFuWengParamType;
import com.yanqu.road.entity.enums.eItemId;
import com.yanqu.road.entity.player.UserBaseInfo;
import com.yanqu.road.entity.rank.cross.CrossUserRank;
import com.yanqu.road.logic.bussiness.activity.DFWActivityBussiness;
import com.yanqu.road.logic.bussiness.servercenter.ActivityBussiness;
import com.yanqu.road.logic.cross.CrossActivityRankListModel;
import com.yanqu.road.logic.pb.DaFuWengPb;
import com.yanqu.road.logic.pb.PlayerBasePb;
import com.yanqu.road.message.YanQuMessage;
import com.yanqu.road.pb.monopoly.MonopolyProto;
import com.yanqu.road.server.logic.MessageHelper;
import com.yanqu.road.server.manager.config.GoodsMgr;
import com.yanqu.road.server.protocol.ClientProtocol;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.GameProtocol;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.YanQuMessageUtils;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

public class DaFuWengActivity {

    private static final Logger logger = LoggerFactory.getLogger(DaFuWengActivity.class);

    private int groupId;

    private DFWCrossConfig crossConfig;

    private DFWCrossData crossData;

    private Object lockObject = new Object();

    // BossId，榜单
    Map<Integer, CrossActivityRankListModel> monsterRankListModelMap;

    // BossId，用户ID，伤害记录
    Map<Integer, Map<Long, DFWAttackRecord>> attackRecordMap;

    public void save() {
        // boss数据
        for (Map<Integer, DFWBossData> bossDataList : crossData.getBossDataMap().values()) {
            for (DFWBossData data : bossDataList.values()) {
                if (data.isInsertOption()) {
                    DFWActivityBussiness.addDFWBossData(data);
                } else if (data.isUpdateOption()) {
                    DFWActivityBussiness.updateDFWBossData(data);
                }
            }
        }
        // 商会情报
        Map<String, List<DFWUnionNews>> unionNewsMap = crossData.getUnionNewsMap();
        for (List<DFWUnionNews> list : unionNewsMap.values()) {
            for (int i = 0; i < list.size(); i++) {
                DFWUnionNews data = list.get(i);
                if (data.isInsertOption()) {
                    DFWActivityBussiness.addDFWUnionNews(data);
                }
            }
        }
        // 伤害信息
        for (Map<Long, DFWAttackRecord> map : attackRecordMap.values()) {
            for (DFWAttackRecord record : map.values()) {
                if (record.isInsertOption()) {
                    DFWActivityBussiness.addDFWAttackRecord(record);
                } else if (record.isUpdateOption()) {
                    DFWActivityBussiness.updateDFWAttackRecord(record);
                }
            }
        }

        long nowTime = System.currentTimeMillis() / 1000;
        if(nowTime >= (getCrossConfig().getActivityInfo().getEndTime() + 60 * 60)){
            if (crossData.getBossDataMap().size() > 0 || crossData.getUnionNewsMap().size() > 0) {
                LogManager.getLogger(DaFuWengActivity.class.getName()).debug("remove expired data {} {} {}", getCrossConfig().getActivityInfo().getActivityId(), crossData.getUnionNewsMap().size(), crossData.getBossDataMap().size());
                crossData.setUnionNewsMap(new ConcurrentHashMap<>());
                crossData.setBossDataMap(new ConcurrentHashMap<>());
            }

        }
    }

    /**
     * 新活动
     */
    public DaFuWengActivity(ActivityInfo activityInfo, int groupId) {
        int activityId = activityInfo.getActivityId();
        DFWCrossData tmpData = new DFWCrossData();
        DFWCrossConfig tmpConfig;

        this.groupId = groupId;

        // 【配置】
        tmpConfig = createDFWCrossConfig(activityInfo);

        // 【数据】
        tmpData.setActivityId(activityId);
        // boss数据
        tmpData.setBossDataMap(DFWActivityBussiness.getDFWBossDataMap(activityId, groupId));
        tmpData.setUnionNewsMap(DFWActivityBussiness.getDFWUnionNewsList(activityId, groupId));

        // 找bossId边界
        int maxBossId = 0;
        int minEffectiveBossId = Integer.MAX_VALUE;
        long lastTime = System.currentTimeMillis() - DaFuWengMgr.CLEAN_INTERVAL;
        for (Map<Integer, DFWBossData> bossDataMap : tmpData.getBossDataMap().values()) {
            for (DFWBossData bossData : bossDataMap.values()) {
                // 最大bossId
                if (bossData.getBossId() > maxBossId) {
                    maxBossId = bossData.getBossId();
                }
                // 有效boss最小Id（存活、死亡不超过一段时间）
                if ((bossData.getCurHp() > 0 || bossData.getKillTime() > lastTime) &&
                        bossData.getBossId() < minEffectiveBossId) {
                    minEffectiveBossId = bossData.getBossId();
                }
            }
        }
        if (minEffectiveBossId == Integer.MAX_VALUE) {
            minEffectiveBossId = 0;
        }

        // 设置下个BossId
        tmpData.setNextBossId(new AtomicInteger(1 + maxBossId));

        // 覆盖
        crossConfig = tmpConfig;
        crossData = tmpData;

        // 【攻击记录】
        Map<Integer, Map<Long, DFWAttackRecord>> tmpAttackRecordMap = DFWActivityBussiness.getDFWAttackRecordMap(activityId, groupId, minEffectiveBossId);
        cleanOldAttackData(tmpAttackRecordMap);
        attackRecordMap = tmpAttackRecordMap;

        // 【榜单】
        monsterRankListModelMap = new ConcurrentHashMap<>();
        initMonsterRankList();
    }

    /**
     * 初始化怪物榜单
     */
    public void initMonsterRankList() {
        for (Map.Entry<Integer, Map<Long, DFWAttackRecord>> entry : attackRecordMap.entrySet()) {
            int bossId = entry.getKey();
            Map<Long, DFWAttackRecord> bossRecordMap = entry.getValue();
            CrossActivityRankListModel model = getMonsterRankListModel(bossId);
            LinkedList<CrossUserRank> rankList = new LinkedList<>();
            for (DFWAttackRecord record : bossRecordMap.values()) {
                CrossUserRank rank = new CrossUserRank();
                rank.setUserBaseInfo(record.getUserBaseInfo());
                rank.setUserId(record.getUserId());
                rank.setLastUpdateTime(record.getUpdateTime());
                rank.setValue(BigInteger.valueOf(record.getDamage()));
                rankList.add(rank);
            }
            if (rankList.size() > 0) {
                model.setRankList(rankList);
            }
        }
    }

    /**
     * 读取配置
     */
    public DFWCrossConfig createDFWCrossConfig(ActivityInfo activityInfo) {
        DFWCrossConfig tmpConfig = new DFWCrossConfig();
        int activityId = activityInfo.getActivityId();

        tmpConfig.setActivityInfo(activityInfo);
        // boss配置
        Map<Integer, DFWBossConfig> tmpBossConfigMap = DFWActivityBussiness.getDFWBossConfigMap(activityId);
        tmpConfig.setBossConfigMap(tmpBossConfigMap);
        // 其他配置
        Map<eDaFuWengParamType, DFWParamConfig> paramConfigMap = DFWActivityBussiness.getDFWParamConfigMap(activityId);
        tmpConfig.setDamageGoldParam(Integer.valueOf(paramConfigMap.get(eDaFuWengParamType.MONOPOLY_BATTLE_REWARD_GOLD_PARAM).getValue()));
        tmpConfig.setEffectiveNewsCount(Integer.valueOf(paramConfigMap.get(eDaFuWengParamType.MONOPOLY_UNION_EFFECTIVE_NEWS_COUNT).getValue()));
        tmpConfig.setUneffectiveNewsCount(Integer.valueOf(paramConfigMap.get(eDaFuWengParamType.MONOPOLY_UNION_UNEFFECTIVE_NEWS_COUNT).getValue()));
        // 佣兵卡伤害
        GoodsInfo goodsInfo = GoodsMgr.getGoodsInfo(eItemId.DFW_YONG_BING_CARD.getValue());
        int eventId = Integer.valueOf(goodsInfo.getExtendParam().split(";")[0]);
        Map<Integer, DFWEvent> eventMap = DFWActivityBussiness.getDFWEventConfigMap(activityId);
        tmpConfig.setYongBingCardDamage(eventMap.get(eventId).getParamList().get(0));
        return tmpConfig;
    }

    public void repair() {
        // 同一个activityId的全部group都会调用
    }

    /**
     * 重新加载配置
     */
    public void reloadConfig() {
        int activityId = crossConfig.getActivityInfo().getActivityId();
        ActivityInfo tmpActivityInfo = ActivityBussiness.getActivityInfoByActivityId(activityId);
        DFWCrossConfig tmpConfig = createDFWCrossConfig(tmpActivityInfo);
        // 覆盖
        crossConfig = tmpConfig;
        logger.info("Cross DaFuWengActivity reload config success!");
    }

    /**
     * 根据权重获取BossId
     */
    public int getRandomAliveBossId() {
        synchronized (lockObject) {
            Random random = new Random();
            // 随机权重找boss类型配置
            List<Integer> weight = new ArrayList<>();
            List<DFWBossConfig> bossConfigList = new ArrayList<>(crossConfig.getBossConfigMap().values());
            for (DFWBossConfig map : bossConfigList) {
                weight.add(map.getWeight());
            }
            int index = RandomHelper.getRandomIndexByWeight(weight, random);
            DFWBossConfig bossConfig = bossConfigList.get(index);

            // 获取该类型存活的boss
            if (!crossData.getBossDataMap().containsKey(bossConfig.getBossType())) {
                crossData.getBossDataMap().put(bossConfig.getBossType(), new ConcurrentHashMap<>());
            }
            List<DFWBossData> copyBossDataList = new ArrayList<>(crossData.getBossDataMap().get(bossConfig.getBossType()).values());
            List<DFWBossData> aliveBossList = new ArrayList<>();
            for (DFWBossData bossData : copyBossDataList) {
                if (bossData.getKillerUserId() == 0) {
                    aliveBossList.add(bossData);
                }
            }

            // 判断是需要生成boss
            if (aliveBossList.isEmpty()) {
                // 如果没boss，则生成一批
                synchronized (lockObject) {
                    // 防重复生成
                    if (copyBossDataList.size() == crossData.getBossDataMap().get(bossConfig.getBossType()).size()) {
                        createBatchBoss(bossConfig.getBossType());
                    }
                    // 把鲜活的boss加进来
                    int oldSize = copyBossDataList.size();
                    copyBossDataList = new ArrayList<>(crossData.getBossDataMap().get(bossConfig.getBossType()).values());
                    for (int i = 0; i < copyBossDataList.size(); i++) {
                        DFWBossData data = copyBossDataList.get(i);
                        if (data.getKillerUserId() == 0) {
                            aliveBossList.add(data);
                        }
                    }
                }
            }
            if (aliveBossList.isEmpty()) {
                logger.error("Cross2Server DaFuWengActivity getRandomAliveBossId error, Maybe in create boss!");
                return 0;
            }

            // 抽boss
            return aliveBossList.get(random.nextInt(aliveBossList.size())).getBossId();
        }
    }

    /**
     * 通过bossId获取boss数据
     */
    public DFWBossData getBossDataById(int bossId) {
        for (Map<Integer, DFWBossData> map : crossData.getBossDataMap().values()) {
            if (map.containsKey(bossId)) {
                return map.get(bossId);
            }
        }
        return null;
    }

    /**
     * 通过Boss类型获取boss配置
     */
    private DFWBossConfig getBossConfig(int bossType) {
        return crossConfig.getBossConfigMap().get(bossType);
    }

    /**
     * 生成一批新的boss
     */
    private void createBatchBoss(int type) {
        if (!crossData.getBossDataMap().containsKey(type)) {
            crossData.getBossDataMap().put(type, new ConcurrentHashMap<>());
        }
        Map<Integer, DFWBossData> bossDataMap = crossData.getBossDataMap().get(type);
        // 找批次
        int batch = 0;
        int activityId = crossConfig.getActivityInfo().getActivityId();
        for (DFWBossData bossData : bossDataMap.values()) {
            if (bossData.getBossBatch() > batch) {
                batch = bossData.getBossBatch();
            }
        }
        batch = batch == 0 ? 1 : batch;
        DFWBossConfig bossConfig = crossConfig.getBossConfigMap().get(type);
        int num = bossConfig.getNum();
        for (int i = 0; i < num; i++) {
            DFWBossData data = new DFWBossData();
            data.setActivityId(activityId);
            data.setGroupId(groupId);
            data.setBossBatch(batch);
            data.setBossId(crossData.getNextBossId());
            data.setBossType(type);
            data.setCurHp(bossConfig.getHp());
            data.setKillerPlayer(null);
            data.setKillerUserId(0);
            data.setTotalHp(bossConfig.getHp());
            data.setInsertOption();
            bossDataMap.put(data.getBossId(), data);
        }
    }

    /**
     * 打boss
     */
    public void attackBoss(long serverId, long userId, int bossId, int damage, MonopolyProto.MonopolyPlayerMsg playerBaseDataMsg, int type, int buffTimes, String cost, long yongBingCardNum , int yongBingCardLimit) {
        synchronized (lockObject) {
            DFWBossData bossData = getBossDataById(bossId);
            DFWBossConfig bossConfig = null;
            if (bossData != null) {
                bossConfig = getBossConfig(bossData.getBossType());
            }

            // 异常
            if (bossData == null || bossConfig == null) {
                MonopolyProto.CrossBattleBossRespMsg.Builder respMsg = MonopolyProto.CrossBattleBossRespMsg.newBuilder();
                respMsg.setRet(GameErrorCode.E_ACTIVITY_DFW_BOSS_DEAD);
                respMsg.setType(type);
                respMsg.setBuffTimes(buffTimes);
                respMsg.setCost(cost);
                respMsg.setActivityId(crossConfig.getActivityInfo().getActivityId());
                respMsg.setPreReduceYongBingCardNum(yongBingCardNum);
                YanQuMessage yanQuMessage = YanQuMessageUtils.buildMessage(GameProtocol.S_DA_FU_WENG_BATTLE_BOSS_FROM_CROSS, respMsg);
                MessageHelper.sendPacket(serverId, userId, yanQuMessage);
                return;
            }

            // 已被击杀
            if (bossData.getKillerUserId() != 0) {
                MonopolyProto.CrossBattleBossRespMsg.Builder respMsg = MonopolyProto.CrossBattleBossRespMsg.newBuilder();
                respMsg.setRet(GameErrorCode.E_ACTIVITY_DFW_BOSS_DEAD);
                respMsg.setType(type);
                respMsg.setBuffTimes(buffTimes);
                respMsg.setCost(cost);
                respMsg.setActivityId(crossConfig.getActivityInfo().getActivityId());
                respMsg.setBossData(parseBossDataMsg(bossData));
                respMsg.setPreReduceYongBingCardNum(yongBingCardNum);
                YanQuMessage yanQuMessage = YanQuMessageUtils.buildMessage(GameProtocol.S_DA_FU_WENG_BATTLE_BOSS_FROM_CROSS, respMsg);
                MessageHelper.sendPacket(serverId, userId, yanQuMessage);
                return;
            }
            damage += DaFuWengDataMgr.getBattleSkillAddition(crossConfig.getActivityInfo().getActivityId(), playerBaseDataMsg.getPlayer().getUnionUid());

            // 实际伤害
            int realDamage = bossData.getCurHp() < damage ? bossData.getCurHp() : damage;

            int remainBlood = bossData.getCurHp() - realDamage;
            // 计算可用的佣兵卡数量
            long useYongBingCardNum = 0;
            if(remainBlood > 0 && yongBingCardNum > 0){
                //4.8新增快速击杀boss,最多使用n张佣兵卡(默认10)能杀的话才能打
                if (type == 4) {
                    int needYongBingCardNum = (remainBlood + getCrossConfig().getYongBingCardDamage() - 1) / getCrossConfig().getYongBingCardDamage();
                    //如果需要的佣兵卡 > 配置里快速击杀限制使用的佣兵卡数量
                    if (needYongBingCardNum > yongBingCardLimit) {
                        MonopolyProto.CrossBattleBossRespMsg.Builder respMsg = MonopolyProto.CrossBattleBossRespMsg.newBuilder();
                        respMsg.setRet(GameErrorCode.E_ACTIVITY_DFW_FAST_KILL_LIMIT_YONG_BING_CARD_NO_KILL);
                        respMsg.setType(type);
                        respMsg.setBuffTimes(buffTimes);
                        respMsg.setCost(cost);
                        respMsg.setActivityId(crossConfig.getActivityInfo().getActivityId());
                        respMsg.setBossData(parseBossDataMsg(bossData));
                        respMsg.setPreReduceYongBingCardNum(yongBingCardNum);
                        YanQuMessage yanQuMessage = YanQuMessageUtils.buildMessage(GameProtocol.S_DA_FU_WENG_BATTLE_BOSS_FROM_CROSS, respMsg);
                        MessageHelper.sendPacket(serverId, userId, yanQuMessage);
                        return;
                    }
                    //如果需要的佣兵卡数量大于背包中的数量，无法快速击杀
                    if (needYongBingCardNum > yongBingCardNum) {
                        MonopolyProto.CrossBattleBossRespMsg.Builder respMsg = MonopolyProto.CrossBattleBossRespMsg.newBuilder();
                        respMsg.setRet(GameErrorCode.E_ACTIVITY_DFW_ITEM_NO_ENOUGH);
                        respMsg.setType(type);
                        respMsg.setBuffTimes(buffTimes);
                        respMsg.setCost(cost);
                        respMsg.setActivityId(crossConfig.getActivityInfo().getActivityId());
                        respMsg.setBossData(parseBossDataMsg(bossData));
                        respMsg.setPreReduceYongBingCardNum(yongBingCardNum);
                        YanQuMessage yanQuMessage = YanQuMessageUtils.buildMessage(GameProtocol.S_DA_FU_WENG_BATTLE_BOSS_FROM_CROSS, respMsg);
                        MessageHelper.sendPacket(serverId, userId, yanQuMessage);
                        return;
                    }
                    //使用的佣兵卡数量 = 击杀boss需要的数量
                    useYongBingCardNum = needYongBingCardNum;
                    long yongBingCardDamage = useYongBingCardNum * getCrossConfig().getYongBingCardDamage();
                    long realYongBingCardDamage = remainBlood < yongBingCardDamage ? remainBlood : yongBingCardDamage;
                    realDamage += realYongBingCardDamage;


                } else {      // 未被击杀 且 使用了佣兵卡 正常打
                    int needYongBingCardNum = (remainBlood + getCrossConfig().getYongBingCardDamage() - 1) / getCrossConfig().getYongBingCardDamage();
                    useYongBingCardNum = Math.min(needYongBingCardNum, yongBingCardNum);
                    long yongBingCardDamage = useYongBingCardNum * getCrossConfig().getYongBingCardDamage();
                    long realYongBingCardDamage = remainBlood < yongBingCardDamage ? remainBlood : yongBingCardDamage;
                    realDamage += realYongBingCardDamage;
                }
            }
            bossData.setCurHp(bossData.getCurHp() - realDamage);
            // 是否击杀
            boolean isKill = bossData.getCurHp() <= 0;
            if (isKill) {
                bossData.setKillerUserId(userId);
                bossData.setKillerPlayer(PlayerBasePb.parseBaseUserInfo(playerBaseDataMsg.getPlayer()));
                bossData.setKillTime(System.currentTimeMillis());
            }

            // 加入榜单
            addAttackRecord(bossId, userId, serverId, PlayerBasePb.parseBaseUserInfo(playerBaseDataMsg.getPlayer()), realDamage);

            // 计算奖励
            Property property = new Property();
            property.addProperty(eItemId.DFW_GOLDEN.getValue(), BigInteger.valueOf(new BigDecimal(realDamage).multiply(new BigDecimal(crossConfig.getDamageGoldParam())).divide(new BigDecimal(1000), 0, BigDecimal.ROUND_UP).longValue()));
            if (isKill) {
                property.addProperty(PropertyHelper.parseStringToProperty(bossConfig.getRewards()));
            }

            // 返回
            MonopolyProto.CrossBattleBossRespMsg.Builder builder = MonopolyProto.CrossBattleBossRespMsg.newBuilder();
            builder.setRet(0);
            builder.setType(type);
            builder.setBuffTimes(buffTimes);
            builder.setCost(cost);
            builder.setActivityId(crossConfig.getActivityInfo().getActivityId());
            builder.setBossData(parseBossDataMsg(bossData));
            builder.setIsKill(isKill);
            builder.setRealDamage(realDamage);
            builder.setPreReduceYongBingCardNum(yongBingCardNum);
            builder.setConsumeYongBingCardNum(useYongBingCardNum);

            builder.setReward(PropertyHelper.parsePropertyToString(property));
            YanQuMessage yanQuMessage = YanQuMessageUtils.buildMessage(GameProtocol.S_DA_FU_WENG_BATTLE_BOSS_FROM_CROSS, builder);
            MessageHelper.sendPacket(serverId, userId, yanQuMessage);
        }
    }


    public DfwAttackBossResult tenRollShareAndAttackBoss(long serverId, long userId, int damage, MonopolyProto.MonopolyPlayerMsg playerBaseDataMsg) {
        synchronized (lockObject) {
            int bossId = getRandomAliveBossId();
            DFWBossData bossData = getBossDataById(bossId);
            DFWBossConfig bossConfig = getBossConfig(bossData.getBossType());
            damage += DaFuWengDataMgr.getBattleSkillAddition(crossConfig.getActivityInfo().getActivityId(), playerBaseDataMsg.getPlayer().getUnionUid());
            // 实际伤害
            int realDamage = bossData.getCurHp() < damage ? bossData.getCurHp() : damage;
            bossData.setCurHp(bossData.getCurHp() - realDamage);

            // 是否击杀
            boolean isKill = bossData.getCurHp() <= 0;
            if (isKill) {
                bossData.setKillerUserId(userId);
                bossData.setKillerPlayer(PlayerBasePb.parseBaseUserInfo(playerBaseDataMsg.getPlayer()));
                bossData.setKillTime(System.currentTimeMillis());
            }

            // 加入榜单
            addAttackRecord(bossId, userId, serverId, PlayerBasePb.parseBaseUserInfo(playerBaseDataMsg.getPlayer()), realDamage);

            // 计算奖励
            Property property = new Property();
            property.addProperty(eItemId.DFW_GOLDEN.getValue(), BigInteger.valueOf(new BigDecimal(realDamage).multiply(new BigDecimal(crossConfig.getDamageGoldParam())).divide(new BigDecimal(1000), 0, BigDecimal.ROUND_UP).longValue()));
            if (isKill) {
                property.addProperty(PropertyHelper.parseStringToProperty(bossConfig.getRewards()));
            }
            String unionUid = playerBaseDataMsg.getPlayer().getUnionUid();
            // 添加商会情报
            if (!StringUtils.isNullOrEmpty(unionUid)) {
                addUnionNews(serverId, userId, unionUid, bossId);
            }
            DfwAttackBossResult result = new DfwAttackBossResult(property, realDamage);
            result.setBossId(bossId);
            result.setBossType(bossData.getBossType());
            result.setKill(isKill);
            return result;
        }
    }



    /**
     * 转换boss数据
     */
    public static MonopolyProto.BossDataMsg parseBossDataMsg(DFWBossData bossData) {
        MonopolyProto.BossDataMsg.Builder builder = MonopolyProto.BossDataMsg.newBuilder();
        builder.setBossId(bossData.getBossId());
        builder.setCurHp(bossData.getCurHp());
        builder.setBossType(bossData.getBossType());
        boolean isKill = bossData.getKillerUserId() != 0;
        builder.setIsKill(isKill);
        if (isKill) {
            builder.setMonopolyPlayer(DaFuWengPb.parseMonopolyPlayerMsg(bossData.getKillerUserId(), bossData.getKillerPlayer()));
        }
        return builder.build();
    }

    /**
     * 添加商会情报
     */
    public int addUnionNews(long serverId, long userId, String unionUid, int bossId) {
        synchronized (lockObject) {
            Map<String, List<DFWUnionNews>> unionNewsMap = crossData.getUnionNewsMap();
            if (!unionNewsMap.containsKey(unionUid)) {
                unionNewsMap.put(unionUid, new ArrayList<>());
            }
            List<DFWUnionNews> unionNewsList = unionNewsMap.get(unionUid);
            // boss挂了直接分享到无效情报中
            DFWBossData bossData = getBossDataById(bossId);
            if (bossData.getKillerUserId() != 0) {
                for (int i = unionNewsList.size() - 1; i >= 0; i--) {
                    if (unionNewsList.get(i).getBossId() == bossId) {
                        return 3; // 已有这只死boss了
                    }
                }
                unionNewsList.add(new DFWUnionNews(crossConfig.getActivityInfo().getActivityId(), groupId, unionUid, bossId, System.currentTimeMillis()));
                return 1; // 成功分享这只死boss
            }
            // 判断有效情报数量
            int efMaxCount = crossConfig.getEffectiveNewsCount();
            int efCount = 0;
            for (int i = unionNewsList.size() - 1; i >= 0; i--) {
                int tmpBossId = unionNewsList.get(i).getBossId();
                if (tmpBossId == bossId) {
                    // 已经有这条情报了
                    return 3;
                }
                DFWBossData tempBossData = getBossDataById(tmpBossId);
                if (tempBossData != null && tempBossData.getKillerUserId() == 0) {
                    efCount++;
                }
                if (efCount >= efMaxCount) {
                    // 有效情报数量满了
                    return 2;
                }
            }
            // 有效情报未满
            unionNewsList.add(new DFWUnionNews(crossConfig.getActivityInfo().getActivityId(), groupId, unionUid, bossId, System.currentTimeMillis()));
            syncUnionNewsRedHot(serverId, userId, unionUid);
            return 1;
        }
    }

    /**
     * 获取商会情报
     */
    public void getUnionNews(String unionUid, long serverId, long userId) {
        synchronized (lockObject) {
            Map<String, List<DFWUnionNews>> unionNewsMap = crossData.getUnionNewsMap();
            if (!unionNewsMap.containsKey(unionUid)) {
                unionNewsMap.put(unionUid, new ArrayList<>());
            }
            List<DFWUnionNews> unionNewsList = unionNewsMap.get(unionUid);
            int efMaxCount = crossConfig.getEffectiveNewsCount();
            int unefMaxCount = crossConfig.getUneffectiveNewsCount();

            // 筛选情报
            List<MonopolyProto.BossDataMsg> efList = new ArrayList<>();
            List<MonopolyProto.BossDataMsg> unefList = new ArrayList<>();
            List<DFWBossData> unefBossList = new ArrayList<>();
            for (int i = unionNewsList.size() - 1; i >= 0; i--) {
                DFWBossData bossData = getBossDataById(unionNewsList.get(i).getBossId());
                if (bossData.getKillerUserId() == 0) {
                    if (efList.size() < efMaxCount) {
                        efList.add(parseBossDataMsg(bossData));
                    }
                } else {
                    unefBossList.add(bossData);
                }
            }
            // 无效情报按时间排序
            List<DFWBossData> collect = unefBossList.stream().sorted(Comparator.comparing(DFWBossData::getKillTime).reversed()).collect(Collectors.toList());
            for (int i = 0; i < collect.size() && i < unefMaxCount; i++) {
                unefList.add(parseBossDataMsg(collect.get(i)));
            }

            MonopolyProto.GetUnionNewsRespMsg.Builder builder = MonopolyProto.GetUnionNewsRespMsg.newBuilder();
            builder.setRet(0);
            builder.addAllEffectiveList(efList);
            builder.addAllUnEffectiveList(unefList);
            YanQuMessage bufMessage = YanQuMessageUtils.buildMessage(ClientProtocol.U_DA_FU_WENG_GET_UNION_NEWS, builder);
            MessageHelper.sendPacket(serverId, userId, bufMessage);
            return;
        }
    }

    /**
     * 获取怪物伤害榜单
     */
    public CrossActivityRankListModel getMonsterRankListModel(int monsterId) {
        synchronized (lockObject) {
            if (!monsterRankListModelMap.containsKey(monsterId)) {
                CrossActivityRankListModel model = new CrossActivityRankListModel(crossConfig.getActivityInfo().getActivityId(), false);
                model.setRankNum(100);

                // 无效boss直接返回空数据，不加到Map
                DFWBossData bossData = getBossDataById(monsterId);
                long lastTime = System.currentTimeMillis() - DaFuWengMgr.CLEAN_INTERVAL;
                if (bossData == null ||
                        bossData.getCurHp() <= 0 && bossData.getKillTime() != 0 && bossData.getKillTime() < lastTime) {
                    return model;
                }

                monsterRankListModelMap.put(monsterId, model);
            }
        }
        return monsterRankListModelMap.get(monsterId);
    }

    public DFWAttackRecord addAttackRecord(int monsterId, long userId, long serverId, UserBaseInfo userBaseInfo, long damage) {
        if (!attackRecordMap.containsKey(monsterId)) {
            attackRecordMap.put(monsterId, new ConcurrentHashMap<>());
        }
        DFWAttackRecord record = attackRecordMap.get(monsterId).get(userId);
        if (record == null) {
            record = new DFWAttackRecord();
            record.setActivityId(crossConfig.getActivityInfo().getActivityId());
            record.setGroupId(groupId);
            record.setMonsterId(monsterId);
            record.setServerId(serverId);
            record.setUserId(userId);
            record.setDamage(0);
            record.setUpdateTime(0);
            record.setUserBaseInfo(userBaseInfo);
            record.setInsertOption();
            attackRecordMap.get(monsterId).put(userId, record);
        }

        record.setUpdateTime(System.currentTimeMillis());
        record.setDamage(record.getDamage() + damage);
        record.setUserBaseInfo(userBaseInfo);

        CrossActivityRankListModel model = getMonsterRankListModel(monsterId);
        CrossUserRank rank = new CrossUserRank();
        rank.setUserBaseInfo(record.getUserBaseInfo());
        rank.setUserId(record.getUserId());
        rank.setLastUpdateTime(record.getUpdateTime());
        rank.setValue(BigInteger.valueOf(record.getDamage()));
        model.rankChange(rank);
        return record;
    }

    public void syncUnionNewsRedHot(long serverId, long userId, String unionUid) {
        MonopolyProto.DaFuWengUnionNewsRedHotFromCrossReqMsg.Builder req = MonopolyProto.DaFuWengUnionNewsRedHotFromCrossReqMsg.newBuilder();
        req.setUnionUid(unionUid);
        YanQuMessage bufMessage = YanQuMessageUtils.buildMessage(GameProtocol.S_DA_FU_WENG_UNION_NEWS_RED_HOT_NOTIFY_FROM_CROSS, req);
        MessageHelper.sendPacket(serverId, userId, bufMessage);
    }

    public DFWCrossConfig getCrossConfig() {
        return crossConfig;
    }

    public void setCrossConfig(DFWCrossConfig crossConfig) {
        this.crossConfig = crossConfig;
    }

    /**
     * 清空活动旧数据
     */
    public void cleanActivityOldData() {
        Map<Integer, CrossActivityRankListModel> rankMap = this.monsterRankListModelMap;
        if (rankMap != null) {
            cleanOldRankData(rankMap);
        }

        Map<Integer, Map<Long, DFWAttackRecord>> recordMap = this.attackRecordMap;
        if (recordMap != null) {
            cleanOldAttackData(recordMap);
        }
    }

    /**
     * 清空旧榜单数据
     */
    public void cleanOldRankData(Map<Integer, CrossActivityRankListModel> rankMap) {
        long lastTime = System.currentTimeMillis() - DaFuWengMgr.CLEAN_INTERVAL;

        List<Integer> bossIdList = new ArrayList<>();
        for (Map.Entry<Integer, CrossActivityRankListModel> rankEntry : rankMap.entrySet()) {
            Integer bossId = rankEntry.getKey();
            DFWBossData bossData = getBossDataById(bossId);
            if (bossData == null ||
                    (bossData.getCurHp() <= 0 && bossData.getKillTime() < lastTime)) {
                bossIdList.add(bossId);
            }
        }

        for (Integer bossId : bossIdList) {
            rankMap.remove(bossId);
        }
    }

    /**
     * 清空旧攻击记录数据
     */
    public void cleanOldAttackData(Map<Integer, Map<Long, DFWAttackRecord>> attackRecordMap) {
        long lastTime = System.currentTimeMillis() - DaFuWengMgr.CLEAN_INTERVAL;

        List<Integer> bossIdList = new ArrayList<>();
        for (Map.Entry<Integer, Map<Long, DFWAttackRecord>> mapEntry : attackRecordMap.entrySet()) {
            Integer bossId = mapEntry.getKey();
            DFWBossData bossData = getBossDataById(bossId);
            if (bossData == null ||
                    (bossData.getCurHp() <= 0 && bossData.getKillTime() < lastTime)) {
                bossIdList.add(bossId);
            }
        }

        for (Integer bossId : bossIdList) {
            attackRecordMap.remove(bossId);
        }
    }

}
